<template>
  <div ref="main_tabs" class="jp-content">
    <div v-show="dropdown_visible" :style="style" class="sea-dropdown-menu">
      <p class="el-dropdown-menu__item" id="sea-tabs-close-current">关闭当前</p>
      <p class="el-dropdown-menu__item" id="sea-tabs-close-left">关闭左边</p>
      <p class="el-dropdown-menu__item" id="sea-tabs-close-right">关闭右边</p>
      <hr/>
      <p class="el-dropdown-menu__item" id="sea-tabs-close-other">关闭其他</p>
      <p class="el-dropdown-menu__item" id="sea-tabs-close-all">关闭所有</p>
    </div>

    <el-tabs type="card" v-model="current_tabs_name" class="sea-tabs"
             @contextmenu.prevent.native="onTabRightClick"
             @tab-click="onTabClick" @tab-remove="onTabRemove">

      <!-- 注意：这里简化了逻辑，直接将 path 作为 name， 可能有潜在的编码问题-->
      <el-tab-pane v-for="item in menu_tabs" :key="item.id"
                   :label="item.label" :name="item.path" closable>
        <div :style="body">
          <keep-alive>
            <router-view v-if="item.vasiblty"/>
          </keep-alive>
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import MenuManager from "../../starter/menu-manager";

/**
 * 中央选项卡
 */
export default {
    name: "center-tabs"
    , props: {
        // 面板宽度
        width: {type: [Number, String], default: undefined}
        // 面板高度
        , height: {type: [Number, String], default: undefined}
    }
    , data() {
        return {
            // 右击菜单可见性
            dropdown_visible: false
            // 右击事件的选项卡 name
            , dropdown_name: undefined
            // 右击菜单位置
            , left: undefined
            // 右击菜单位置
            , top: undefined

            // 选项卡数据列表
            , menu_tabs: []
            // 完整的路由信息
            , fully_routes: MenuManager.fully_routes
            // 当前展示的选项卡
            , current_tabs_name: '/'

            // 主面板对象
            , main_tabs: undefined
        }
    },
    watch: {
        $route: {
            /**
             * 侦听路由变化，更新选项卡数据
             */
            handler(val) {
                if (val.path !== 'ignore' && val.path !== '/') {
                    let target = this.routeTo({path: val.path});
                    this.current_tabs_name = target.path;
                }
            }
            , immediate: true
            , deep: false
        }
    },
    computed: {
        /**
         * 中央面板的宽高，计算这个值很麻烦，现在这样基本就是最优解
         */
        body: function (){
            let a = this.width, b = this.height - 60;
            return "width: " + a + "px; height: " + b + "px;overflow-y: auto;";
        },
        /**
         * 下拉列表框的位置信息
         */
        style: function () {
            return "left: " + this.left - 30 + "px; top: " + this.top + "px;";
        }
    },
    created() {
        if (Layers.isEmpty(this.fully_routes)) {
            this.loadMenus().then((menus) => {
                this.fully_routes = MenuManager.converterMenusToRoutes(menus);
            });
        }
    },
    mounted() {
        // 落下鼠标时，需要移除展开的右击菜单
        window.addEventListener('mousedown', this.onWindowsMousedown);
    },
    methods: {
        /**
         * 记录路由信息
         *
         * @param opts 路由参数
         * @return 返回路由的配置信息
         */
        routeTo: function (opts) {
            let name, path;
            if (opts instanceof String) {
                path = opts;
            } else {
                path = opts.path;
                name = opts.name;
            }

            // 展开的路由配置信息
            let target = undefined;

            // 检测是否已经在展示列表中
            for (let i = 0; i < this.menu_tabs.length; i++) {
                let ele = this.menu_tabs[i];
                if (ele.path === path || ele.name === name) {
                    target = ele;
                    target.vasiblty = true;
                } else {
                    ele.vasiblty = false;
                }
            }

            // 已展示列表中不存在目标界面，尝试从全局路由中查找，并将数据推入列表中
            if (target === undefined) {
                for (let i = 0; i < this.fully_routes.length; i++) {
                    let ele = this.fully_routes[i];
                    if (ele.path === path || ele.name === name) {
                        // 找到就将目标界面推入栈中
                        target = ele;
                        target.vasiblty = true;
                        this.menu_tabs.push(target);
                        break;
                    }
                }
            }

            if (target === undefined) {
                // 如果仍未找到，只能是逻辑错误
                throw new NullPointerException("routes is undefined: " + JSON.stringify(opts));
            } else {
                // 启动路由
                return target;
            }
        },
        /**
         * 移除路由信息
         *
         * @param opts 路由参数
         * @return 移除之后，返回一个最相近的一个路由
         */
        removeRoute(opts) {
            let name, path;
            if (opts instanceof String) {
                path = opts;
            } else {
                path = opts.path;
                name = opts.name;
            }

            for (let i = 0; i < this.menu_tabs.length; i++) {
                let ele = this.menu_tabs[i];
                if (ele.path === path || ele.name === name) {
                    // 截断数组，从菜单列表移除路由信息
                    this.menu_tabs.splice(i, 1);

                    // 如果移除的元素，正好是打开的界面，则返回最接近的一个界面
                    if (ele.vasiblty === true) {
                        if (i > 0) {
                            return this.menu_tabs[i - 1];
                        } else if (i < this.menu_tabs.length) {
                            return this.menu_tabs[i];
                        } else {
                            return undefined;
                        }
                    }
                }
            }
        },

        /**
         * 右击事件 - 打开选项卡右击菜单
         *
         * name 记录在标签的 aria-controls 字段，格式为 "pane-[name]"
         *
         * @param e 事件
         */
        onTabRightClick(e) {
            if (e.target.id !== '') {
                let controls = e.target.getAttribute('aria-controls');
                if (controls.length > 5) {
                    // 记录右击触发的选项卡名称
                    this.dropdown_name = controls.substring(5);
                    this.dropdown_visible = true;

                    this.left = e.clientX;
                    this.top = e.clientY;
                } else {
                    // 不合常理的右击事件
                    console.error('unknown aria-controls: ' + controls);
                }
            }
        },

        /**
         * 关闭选项卡右击菜单
         *
         * 下拉列表的点击事件与当前事件冲突，在这个事件里触发点击事件
         */
        onWindowsMousedown: function (e) {
            let clazz = e.target.getAttribute('class');
            let id = e.target.getAttribute('id');
            if (clazz === 'el-dropdown-menu__item') {
                if (id === 'sea-tabs-close-current') {
                    this.closeCurrentTab();
                } else if (id === 'sea-tabs-close-left') {
                    this.closeLeftTab();
                } else if (id === 'sea-tabs-close-right') {
                    this.closeRightTab();
                } else if (id === 'sea-tabs-close-other') {
                    this.closeOther();
                } else if (id === 'sea-tabs-close-all') {
                    this.closeAll();
                }
            }

            this.dropdown_visible = false;
            this.dropdown_name = undefined;
        },

        /**
         * 关闭当前选项卡
         */
        closeCurrentTab() {
            let path = this.dropdown_name;
            this.removeRoute({path: path});
        },

        /**
         * 关闭左侧选项卡
         */
        closeLeftTab() {
            let path = this.dropdown_name;

            // 当前窗口在不在列表中？
            let flag = false;

            for (let i = 0; i < this.menu_tabs.length; i++) {
                let ele = this.menu_tabs[i];

                // 确定当前窗口是不是在列表中
                if (ele.path === this.current_tabs_name) {
                    flag = true;
                }

                if (ele.path === path) {
                    this.menu_tabs.splice(0, i);

                    // 当前展示的界面被删除，界面跳转到展开下拉框的界面
                    if (flag) {
                        this.$router.push({path: path});
                    }
                }
            }
        },

        /**
         * 关闭右侧选项卡
         */
        closeRightTab() {
            let path = this.dropdown_name;

            // 当前窗口在不在列表中？
            let flag = false;

            for (let i = 0; i < this.menu_tabs.length; i++) {
                let ele = this.menu_tabs[i];

                // 确定当前窗口是不是在列表中
                if (ele.path === this.current_tabs_name) {
                    flag = true;
                }

                if (ele.path === path) {
                    let n = i + 1;
                    if (n < this.menu_tabs.length) {
                        this.menu_tabs.splice(n, this.menu_tabs.length - n);

                        // 当前展示的界面被删除，界面跳转到展开下拉框的界面
                        if (!flag) {
                            this.$router.push({path: path});
                        }
                    }
                }
            }
        },
        /**
         * 关闭其它选项卡
         */
        closeOther() {
            let path = this.dropdown_name;

            for (let i = 0; i < this.menu_tabs.length; i++) {
                let ele = this.menu_tabs[i];

                if (ele.path === path) {
                    this.menu_tabs = [ele];

                    // 当前展示的界面被删除，界面跳转到展开下拉框的界面
                    if (path !== this.current_tabs_name) {
                        this.$router.push({path: path});
                    }
                }
            }
        },
        /**
         * 关闭全部选项卡
         */
        closeAll() {
            this.menu_tabs = [];
            this.current_tabs_name = '/';
        },

        /**
         * 选项卡关闭事件
         *
         * @param path tab页的名称
         */
        onTabRemove(path) {
            let next = this.removeRoute({path: path});
            if (next !== undefined) {
                this.$router.push({path: next.path});
            }
        },

        /**
         * 选项卡点击事件
         *
         * @param dom tab页的对象实例
         */
        onTabClick(dom) {
            let path = dom.name;
            this.$router.push({path: path});
        }
    }
    , destroyed() {
        // 移除鼠标落下的侦听事件
        this.dropdown_visible = false;
        window.removeEventListener('mousedown', this.onWindowsMousedown);
    }
}
</script>

<style scoped>
.sea-dropdown-menu {
    position: fixed;
    width: 150px;
    background-color: #fff;
    z-index: 1024;
    border-radius: 3px;
    -webkit-box-shadow: 1px 2px 10px #ccc;
    box-shadow: 1px 2px 10px #ccc;
}
</style>